;------------------------------------------------------------------------------
;
; As yet untitled
; The Calodox 1k ZX81 Intro
; Copyright (c) 2003 Sebastian Gerlach
;
; 4. Octaedron
;
; Displays rotating 3D octaedrons. Yeah!
;
;------------------------------------------------------------------------------

.z80            ;use Z80 instruction set

org 4034h

hoscoff equ 174+3

start_here:
rmat:	
	ld sp, 42feh
	ld ix, traceproc
	
	out (0feh), a
	
; Transposed rotation matrix
; This is executed once on startup, but is just a bunch of nops...
; And we overwrite the first 9 bytes of initialization code as well
		db 0
		db 0,0	
	
loop_around:
	ld hl, (frames)
	inc hl
	ld (frames), hl
	
	ld a, h					; High part of frame counter
	ld h, 40h				; High part of all mod addresses

	cp 6
	jr c, nodie
	
	jr 4000h

nodie:	
	cp 5
	jr c, nodecr
	ld a, l
	cpl
	rrca
	rrca
	rrca
	and 31
	inc a
	ld (modld+1), a
	jr norot

nodecr:
	cp 3
	jr c, noosc
	ld l, hoscdelta+1
	ld (hl), 1
	ld a, (frames)
	cp 192
	jr c, norot
	ld l, voscdelta+1
	ld (hl), 1	
	jr norot
noosc:
	cp 2
	jr c, incren
	inc h
	ld l, rendercount+1
	ld (hl), 12
	dec h
	jr norot
incren:
	cp 1
	jr c, norot
	ld l, angadelta+1
	ld (hl), 2
	ld a, (frames)
	cp 165
	jr c, norot
	ld l, angbdelta+1
	ld (hl), 3	
	jr norot
norot:

	ld hl, hosc
	ld a, (hl)
hoscdelta:
	add 0
	ld (hl), a
	call sine
	sra a
	add hoscoff
	inc l
	ld (hl), a
	inc l
	ld a, (hl)
voscdelta:
	add 0
	ld (hl), a
	call sine
	add 64
	inc l
	ld (hl), a
	
	; Create rotation matrix
	inc l
	ld a, (hl)
angadelta:
	add a,0
	ld (hl), a
	ld b, a
	inc l
	ld a, (hl)	
angbdelta:
	add a,0
	ld (hl), a
	ld c, a
	
	ld a, b
	call cosine
	ld (rmat+3), a
	ld a,b
	call sine
	ld d, a				; d = sin a
	ld a,c
	call cosine
	ld (rmat+0), a
	call fixmul
	neg
	ld (rmat+5), a
	ld a,c
	call sine
	ld (rmat+4), a
	call fixmul
	ld (rmat+1), a
	xor a
	ld (rmat+2), a
	
	; Create transformed vertices
	ld iy, rmat
	ld b, 6
nvert:
	ld a, (iy+0)
	neg
	ld (iy+6), a
	inc iy
	djnz nvert
	
	; Adjust coordinates
	ld b, 12
	ld hl, rmat
nadj:
	ld a, (hl)
	add 64
	rra
	rrca
	and 1fh
	ld (hl), a
	inc l
	djnz nadj

	ld c, 1
	ld iy, edges
plotb:	
	; Wait for retrace	
	ld hl, lflag
	xor a
	ld (hl), a
waittrace:	
	or (hl)
	jr z, waittrace

	; Render vertices
	call clear
	
rendercount:
	ld b, 4
nedge:
	push bc
	call getlc
	ex hl,de
	call getlc
	
	call bresenham
	pop bc
	djnz nedge

	dec c
	jr nz, plotb	
	
	jp loop_around 
	
hosc	db 0
hoscs	db 32+hoscoff
vosc	db 0
voscs	db 64
anga:	db 0
angb:	db 0

frames:	dw 0h

edges:	
	db 0+rmat-4000h,2+rmat-4000h
	db 2+rmat-4000h,6+rmat-4000h
	db 6+rmat-4000h,8+rmat-4000h
	db 8+rmat-4000h,0+rmat-4000h
	db 0+rmat-4000h,4+rmat-4000h
	db 4+rmat-4000h,6+rmat-4000h
	db 6+rmat-4000h,10+rmat-4000h
	db 0+rmat-4000h,10+rmat-4000h
	db 2+rmat-4000h,4+rmat-4000h
	db 4+rmat-4000h,8+rmat-4000h
	db 8+rmat-4000h,10+rmat-4000h
	db 2+rmat-4000h,10+rmat-4000h
	
	
	
;-------------------------------------------------
; getlc
; Load vertex coordinates into hl
; Vertex to load is pointed by (iy)
;-------------------------------------------------
getlc:
	ld a, (iy)			; Load vertex offset
	inc iy				; Increment vertex pointer
	ld (lin2+1), a		; Modify load line
lin2:
	ld hl, (rmat)		; Load into hl
	ret
	
;-------------------------------------------------
; drawproc
; Synchronous screen refresh
;-------------------------------------------------
drawproc:
	ld a, (hoscs)
	call delay

	ld b, 14
hr:	djnz hr
	ld ix, endofline
	ld a, 43h
	ld i, a
	xor a
modld:
	ld d, 32
	ld e, 32
	
nextline:
	jp oneline+8000h						; 10
oneline:	
	ld r,a									; 9
lflag:				; Place lflag here, it will not disturb anyone
	db 0,0,0,0,0,0,0,0						; 64
	ld r,a									; 9
	db 0,0,0,0,0,0,0,0						; 64
	ld r,a									; 9
	db 0,0,0,0,0,0,0,0						; 64
    jp ix									; 8
endofline:									; = 155
	add a, 8
	ld b, 18 ;24
waithere:
	djnz waithere
	inc hl
	nop
	dec e
	dec d
	jr nz, nextline

	ld hl, lflag
	inc (hl)			; Allow main loop to run	
	
	xor a
	or e
	jr z, nowait
nextwait:
	ld a, 255
	call delay
	dec e
	jr nz,nextwait
	
nowait:
	ld a, (voscs)
	add 40+12+3
	
	ld ix, traceproc
	jr doret
	
traceproc:
	in a, (0feh)
	ld b, 80
stupid:
	djnz stupid
	
	ld ix, drawproc
	out (0ffh),a
	
	ld a, (voscs)
	neg
	add 128+52
	
doret:
	jp 029eh
	
;-------------------------------------------------
; fixmul
; Multiply b by c, fixed point 2.6
; In:	d - First value
;		a - Second value		
; Out:	a - Result	
; Mod:	
;-------------------------------------------------
;.comment mul
fixmul:
	push bc
	push de
	ld b, 7
	ld e, a
	bit 7, d
	jr z, ispos
	ld a, d
	neg
	set 7, a
	ld d, a
ispos:
	rlc d
	xor a
nbit:
	rlc d		
	jr nc, zbit
	add e
zbit:	
	sra e 
	djnz nbit	
	rlc d
	jr nc, positive
	neg
positive:
	pop de
	pop bc
	ret
	
;-------------------------------------------------
; bresenham accelerator table
;-------------------------------------------------
	defs 4200h-$
fpoint:
	B0 equ 0c6h+038h
	B1 equ 0c6h+028h
	B2 equ 0c6h+018h
	B3 equ 0c6h+008h
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	db B0, B1, B2, B3
	
;-------------------------------------------------
; clear
; Clears the screen
; Mod:	bc, de, hl
;-------------------------------------------------
clear:	
	push bc
	ld hl, 4300h
	ld (hl), 0
	ld de, 4301h
	ld bc, 255
	ldir
	pop bc
	ret
	
	
;-------------------------------------------------
; bresenham
; Computes points along the line
; In:	de - Start xy coordinates
;		hl - End xy coordinates
; Mod:	a,hl,de,bc
;-------------------------------------------------
bresenham:
	ld bc, 141ch		; inc d / inc e
	
	; Calculate dx
	ld a, h
	sub d
	jr nc, xpos
	neg
	inc b				; dec d
xpos:
	ld h, a
	
	; Calculate dy
	ld a, l
	sub e
	jr nc, ypos
	neg
	inc c				; dec e
ypos:
	ld l, a
	
	; Check dx<dy, flip otherwise
	cp h
	jr c,orderok
	ld a, h				; Exchange h and l (dx and dy)
	ld h, l
	ld l, a
	ld a, b				; Exchande b and c (inc/dec instructions)
	ld b, c
	ld c, a
orderok:
	ld a, b				; Modify code
	ld (bmod0), a
	ld a, c
	ld (bmod1), a
	
	ld a, h
	or l
	ret z
	ld a,h
	srl a
	scf
	
	ld b, h
	
	; h contains delta x
	; l contains delta y
	; a is the error term
	; b is the number of lines left
	; de is current position
npixel:	
	bit 0,b
	jr z,noplot

	push af
	push hl
	ld h, 42h
	ld l, d
	ld a,(hl)
	ld (modh+1),a
	ld a, e
	rlca
	rlca
	rlca
	srl l
	srl l
	add l
	ld l,a
	inc h
modh:
	set 0,(hl)	
	pop hl
	pop af

noplot:	
	sub a, l
bmod0:
	inc d				; Modified!
	dec b
	ret z
	jr nc, npixel
	add a, h
bmod1:
	inc e				; Modified!
	jr npixel
	
	
;-------------------------------------------------
; delay
; Delay for a+x clock cycles
;-------------------------------------------------
delay:
	ld b, a
	and 3
	ld hl, insts
	add l
	ld l, a
	ld a, (hl)
	ld (strt), a
strt:
	nop
	
	srl b
	srl b
	ld a, b
	cpl
	and 3
	ld (jop-1), a
	jr jop		
jop:
	nop
	nop
	nop	
	srl b
	srl b
	ret z
	; Missing 6 cycles because ret not taken
loophere:
	dec b
	jr nz, loophere
	; Missing another 5 cycles because of last jr not taken
	ret z 
	; Takes the 11 cycles we have left :-)
	; Simply ret would have been one cycle too fast for us here

	
insts:
	nop			; 4
	ret c		; 5
	inc hl		; 6
	ld a,(de)	; 7
	
;-------------------------------------------------
; cosine
; Return the cosine of the value in a
; In:	a - Value to take cosine of (from 0 to 255)
; Out:	a - Cosine of input (from 0 to 128)	
; Mod:	None
;-------------------------------------------------
cosine:
	sub 64
;-------------------------------------------------
; sine
; Return the sine of the value in a
; In:	a - Value to take sine of (from 0 to 255)
; Out:	a - Sine of input (from 0 to 128)	
; Mod:	None
;-------------------------------------------------
sine:
	push bc
	push hl	
	ld hl, sinetable
	ld c, a
	bit 6, c
	jr z, s_noflip
	cpl
s_noflip:
	and 3fh
	srl a
	add l
	ld l, a
	ld a, (hl)
	bit 7, c
	jr nz, s_done
	neg
s_done:	
	pop hl
	pop bc
	ret
	
sinetable:
	db  0, 3, 6, 9
	db 12,15,18,21
	db 24,27,30,32
	db 35,38,40,42
	db 45,47,49,51
	db 52,54,56,57
	db 58,59,60,61
	db 62,62,63,63
	
	
	
	
		
end start_here          ;-defines the start address
